package com.kkwrite.regimen.consumer.controller.common;

import com.alibaba.fastjson.JSON;
import com.kkwrite.regimen.common.entity.dto.InDTO;
import com.kkwrite.regimen.common.entity.dto.OutDTO;
import com.kkwrite.regimen.common.entity.dto.decrypt.DecryptPhoneNumInDTO;
import com.kkwrite.regimen.common.entity.dto.file.PictureUploadOutDTO;
import com.kkwrite.regimen.consumer.common.AESUtil;
import com.kkwrite.regimen.consumer.config.SystemConfig;
import com.kkwrite.regimen.consumer.exception.ConsumerException;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * Created by lisha on 2018/7/17 21:09.
 *
 * @author lisha
 */
@RestController
@Api(value = "通用模块")
public class CommonController {

    private final Logger logger = LoggerFactory.getLogger(CommonController.class);

    @Resource(name = "stringRedisTemplate")
    private StringRedisTemplate redisTemplate;
    @Resource(name = "systemConfig")
    private SystemConfig config;

    @PostMapping(value = "/decrypt/phonenum")
    @HystrixCommand(fallbackMethod = "decryptPhoneNumError")
    @ApiOperation(value = "解密手机号信息")
    public OutDTO<String> decryptPhoneNum(@RequestBody InDTO<DecryptPhoneNumInDTO> inDTO, HttpServletRequest request) {
        // 入参校验
        String token = request.getHeader("token");
        Object sessionObj = redisTemplate.opsForHash().get(token, "sessionKey");
        if (sessionObj == null) {
            return new OutDTO<>("false", "002", "token invalid");
        }
        String sessionKey = (String) sessionObj;
        DecryptPhoneNumInDTO dto;
        if (inDTO == null || (dto = inDTO.getBody()).isEmpty()) {
            return new OutDTO<>("false", "入参不合法", null);
        }
        String encryptData = dto.getEncryptData();
        String ivData = dto.getIvData();
        // 解密手机号
        String phoneNo;
        try {
            String decryptResult = AESUtil.decrypt(encryptData, sessionKey, ivData);
            Map jsonMap = JSON.parseObject(decryptResult, Map.class);
            phoneNo = (String) jsonMap.get("purePhoneNumber");
        } catch (GeneralSecurityException e) {
            throw new ConsumerException("解密方法异常");
        }
        return new OutDTO<>("true", null, null, phoneNo);
    }

    public OutDTO<String> decryptPhoneNumError(InDTO<DecryptPhoneNumInDTO> inDTO, HttpServletRequest request) {
        return new OutDTO<>("false", "服务异常！", null);
    }

    @PostMapping(value = "/upload/pictures")
    @HystrixCommand(fallbackMethod = "uploadPicturesError")
    @ApiOperation(value = "上传图片", notes = "可以同时上传多张，参数名为pictures，例如，表单上传时设置name属性值为pictures")
    public OutDTO<PictureUploadOutDTO> uploadPictures(MultipartFile[] pictures, HttpServletRequest request) throws IOException {
        if (pictures.length <= 0) {
            return new OutDTO<>("false", "至少选择一张图片");
        }
        ServletContext servletContext = request.getServletContext();
        for (MultipartFile picture : pictures) {
            if (picture.isEmpty()) {
                return new OutDTO<>("false", "图片内容为空");
            }
            if (!servletContext.getMimeType(picture.getOriginalFilename()).startsWith("image/")) {
                return new OutDTO<>("false", "图片文件格式不正确");
            }
        }
        String yyyyMM = "/" + getYear() + "/" + getMonth();
        String basePath = config.getPicturePathPrefix() + yyyyMM;
        String accessBasePath = config.getAccessPicturePathPrefix() + yyyyMM;
        File baseDirectory = new File(basePath);
        if (!baseDirectory.exists()) {
            if (!baseDirectory.mkdirs()) {
                throw new IOException("图片基础目录创建失败！");
            }
        }
        List<String> pathList = new ArrayList<>();
        List<String> accessPathList = new ArrayList<>();
        for (MultipartFile picture : pictures) {
            String newPictureName = generatePictureName(picture.getOriginalFilename());
            String picturePath = basePath + "/" + newPictureName;
            try {
                FileUtils.copyInputStreamToFile(picture.getInputStream(), new File(picturePath));
            } catch (IOException e) {
                if (pathList.size() > 0) {
                    pathList.forEach((path) -> {
                        try {
                            FileUtils.forceDelete(new File(path));
                        } catch (IOException e1) {
                            logger.error(e1.getMessage(), e1);
                        }
                    });
                }
                throw e;
            }
            pathList.add(picturePath);
            accessPathList.add(accessBasePath + "/" + newPictureName);
        }
        PictureUploadOutDTO out = new PictureUploadOutDTO();
        out.setPaths(accessPathList);
        return new OutDTO<>("true", null, null, out);
    }

    public OutDTO<PictureUploadOutDTO> uploadPicturesError(MultipartFile[] pictures, HttpServletRequest request) {
        return new OutDTO<>("false", "服务异常！");
    }

    private String getYear() {
        return LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy"));
    }

    private String getMonth() {
        return LocalDate.now().format(DateTimeFormatter.ofPattern("MM"));
    }

    private String generatePictureName(String originalFilename) {
        String type = originalFilename.substring(originalFilename.lastIndexOf("."));
        return UUID.randomUUID().toString().replaceAll("-", "").toLowerCase() + type;
    }

}
